use std::time::Duration;
use opentelemetry::{
    global,
    metrics::{Counter as OtelCounter, Histogram as OtelHistogram, MeterProvider, Unit},
    trace::{Span as OtelSpan, SpanKind, Status, TraceContextExt, Tracer as OtelTracer},
    KeyValue,
};
use opentelemetry_otlp::{WithExportConfig, WithMetricsExportConfig, WithTracesExportConfig};
use opentelemetry_sdk::{
    metrics::{SdkMeterProvider, View},
    trace::{Config, Sampler, Tracer},
    Resource,
};
use std::sync::Arc;

use crate::telemetry::{
    metrics::{Counter, Gauge, Histogram, Metrics}, 
    tracing::{Span, SpanContext, SpanStatus, Tracer as TracerTrait},
    TelemetrySystem,
};

/// OpenTelemetry 配置
pub struct OtelConfig {
    /// 服务名称
    pub service_name: String,
    /// 服务版本
    pub service_version: String,
    /// OTLP 端点 (例如: "http://localhost:4317")
    pub endpoint: String,
    /// 跟踪采样率 (0.0 - 1.0)
    pub trace_sample_ratio: f64,
    /// 指标导出间隔（秒）
    pub metrics_export_interval: u64,
    /// 使用 gRPC 而不是 HTTP
    pub use_grpc: bool,
}

impl Default for OtelConfig {
    fn default() -> Self {
        Self {
            service_name: "protoactor-rs".to_string(),
            service_version: env!("CARGO_PKG_VERSION").to_string(),
            endpoint: "http://localhost:4317".to_string(),
            trace_sample_ratio: 1.0,
            metrics_export_interval: 60,
            use_grpc: true,
        }
    }
}

/// OpenTelemetry 导出器
pub struct OtelExporter {
    /// 配置
    pub config: OtelConfig,
    /// 跟踪器
    tracer: Option<OtelTracer>,
    /// 指标提供者
    meter_provider: Option<SdkMeterProvider>,
}

impl OtelExporter {
    /// 创建新的 OpenTelemetry 导出器
    pub fn new(config: OtelConfig) -> Self {
        Self {
            config,
            tracer: None,
            meter_provider: None,
        }
    }
    
    /// 初始化 OpenTelemetry 导出器
    pub fn init(&mut self) -> Result<(), String> {
        // 设置通用资源
        let resource = Resource::new(vec![
            KeyValue::new("service.name", self.config.service_name.clone()),
            KeyValue::new("service.version", self.config.service_version.clone()),
        ]);
        
        // 初始化跟踪器
        let sampler = if self.config.trace_sample_ratio >= 1.0 {
            Sampler::AlwaysOn
        } else if self.config.trace_sample_ratio <= 0.0 {
            Sampler::AlwaysOff
        } else {
            Sampler::TraceIdRatioBased(self.config.trace_sample_ratio)
        };
        
        let trace_config = Config::default().with_sampler(sampler).with_resource(resource.clone());
        
        // 创建 OTLP 导出器
        let tracer = if self.config.use_grpc {
            let exporter = opentelemetry_otlp::new_exporter()
                .tonic()
                .with_endpoint(&self.config.endpoint);
                
            opentelemetry_otlp::new_pipeline()
                .tracing()
                .with_exporter(exporter)
                .with_trace_config(trace_config)
                .install_batch(opentelemetry_sdk::runtime::Tokio)
        } else {
            let exporter = opentelemetry_otlp::new_exporter()
                .http()
                .with_endpoint(&self.config.endpoint);
                
            opentelemetry_otlp::new_pipeline()
                .tracing()
                .with_exporter(exporter)
                .with_trace_config(trace_config)
                .install_batch(opentelemetry_sdk::runtime::Tokio)
        };
        
        if let Err(e) = &tracer {
            return Err(format!("Failed to initialize OpenTelemetry tracer: {}", e));
        }
        
        self.tracer = tracer.ok();
        
        // 初始化指标提供者
        let meter_provider = if self.config.use_grpc {
            let exporter = opentelemetry_otlp::new_exporter()
                .tonic()
                .with_endpoint(&self.config.endpoint);
                
            opentelemetry_otlp::new_pipeline()
                .metrics(opentelemetry_sdk::runtime::Tokio)
                .with_exporter(exporter)
                .with_resource(resource)
                .with_period(Duration::from_secs(self.config.metrics_export_interval))
                .build()
        } else {
            let exporter = opentelemetry_otlp::new_exporter()
                .http()
                .with_endpoint(&self.config.endpoint);
                
            opentelemetry_otlp::new_pipeline()
                .metrics(opentelemetry_sdk::runtime::Tokio)
                .with_exporter(exporter)
                .with_resource(resource)
                .with_period(Duration::from_secs(self.config.metrics_export_interval))
                .build()
        };
        
        if let Err(e) = &meter_provider {
            return Err(format!("Failed to initialize OpenTelemetry meter provider: {}", e));
        }
        
        self.meter_provider = meter_provider.ok();
        
        // 设置全局提供者
        if let Some(mp) = &self.meter_provider {
            global::set_meter_provider(mp.clone());
        }
        
        Ok(())
    }
    
    /// 关闭 OpenTelemetry 导出器
    pub fn shutdown(&self) -> Result<(), String> {
        global::shutdown_tracer_provider();
        if let Some(mp) = &self.meter_provider {
            if let Err(e) = mp.shutdown() {
                return Err(format!("Failed to shutdown meter provider: {}", e));
            }
        }
        Ok(())
    }
    
    /// 获取跟踪器
    pub fn get_tracer(&self) -> Option<&OtelTracer> {
        self.tracer.as_ref()
    }
    
    /// 获取指标提供者
    pub fn get_meter_provider(&self) -> Option<&dyn MeterProvider> {
        self.meter_provider.as_ref().map(|p| p as &dyn MeterProvider)
    }
}

/// OpenTelemetry 指标系统
pub struct OtelMetrics {
    /// 提供者
    provider: Arc<dyn MeterProvider>,
    /// 仪表
    meter: opentelemetry::metrics::Meter,
}

impl OtelMetrics {
    /// 创建新的 OpenTelemetry 指标系统
    pub fn new(provider: Arc<dyn MeterProvider>) -> Self {
        let meter = provider.meter("protoactor-rs");
        Self {
            provider,
            meter,
        }
    }
}

impl Metrics for OtelMetrics {
    fn create_counter(&self, name: &str, description: &str, labels: &[&str]) -> Box<dyn Counter> {
        let counter = self.meter
            .u64_counter(name)
            .with_description(description)
            .init();
            
        Box::new(OtelCounterAdapter { counter })
    }
    
    fn create_gauge(&self, name: &str, description: &str, labels: &[&str]) -> Box<dyn Gauge> {
        let gauge = self.meter
            .f64_gauge(name)
            .with_description(description)
            .init();
            
        Box::new(OtelGaugeAdapter { gauge })
    }
    
    fn create_histogram(&self, name: &str, description: &str, labels: &[&str], buckets: &[f64]) -> Box<dyn Histogram> {
        let histogram = self.meter
            .f64_histogram(name)
            .with_description(description)
            .with_unit(Unit::new("seconds"))
            .init();
            
        Box::new(OtelHistogramAdapter { histogram })
    }
}

/// OpenTelemetry 计数器适配器
struct OtelCounterAdapter {
    counter: OtelCounter<u64>,
}

impl Counter for OtelCounterAdapter {
    fn inc(&self) {
        self.counter.add(1, &[]);
    }
    
    fn inc_with_labels(&self, label_values: &[&str]) {
        self.counter.add(1, &convert_labels(label_values));
    }
    
    fn add(&self, value: f64) {
        self.counter.add(value as u64, &[]);
    }
    
    fn add_with_labels(&self, value: f64, label_values: &[&str]) {
        self.counter.add(value as u64, &convert_labels(label_values));
    }
    
    fn value(&self) -> f64 {
        // 无法直接从 OpenTelemetry 计数器获取值
        0.0
    }
    
    fn value_with_labels(&self, _label_values: &[&str]) -> f64 {
        // 无法直接从 OpenTelemetry 计数器获取值
        0.0
    }
}

/// OpenTelemetry 仪表盘适配器
struct OtelGaugeAdapter {
    gauge: opentelemetry::metrics::Gauge<f64>,
}

impl Gauge for OtelGaugeAdapter {
    fn set(&self, value: f64) {
        self.gauge.record(value, &[]);
    }
    
    fn set_with_labels(&self, value: f64, label_values: &[&str]) {
        self.gauge.record(value, &convert_labels(label_values));
    }
    
    fn inc(&self) {
        // 无法直接增加 OpenTelemetry 仪表盘值
        // 需要先获取当前值，但这在 OpenTelemetry 中不可用
    }
    
    fn inc_with_labels(&self, _label_values: &[&str]) {
        // 无法直接增加 OpenTelemetry 仪表盘值
    }
    
    fn dec(&self) {
        // 无法直接减少 OpenTelemetry 仪表盘值
    }
    
    fn dec_with_labels(&self, _label_values: &[&str]) {
        // 无法直接减少 OpenTelemetry 仪表盘值
    }
    
    fn add(&self, _value: f64) {
        // 无法直接增加 OpenTelemetry 仪表盘值
    }
    
    fn add_with_labels(&self, _value: f64, _label_values: &[&str]) {
        // 无法直接增加 OpenTelemetry 仪表盘值
    }
    
    fn sub(&self, _value: f64) {
        // 无法直接减少 OpenTelemetry 仪表盘值
    }
    
    fn sub_with_labels(&self, _value: f64, _label_values: &[&str]) {
        // 无法直接减少 OpenTelemetry 仪表盘值
    }
    
    fn value(&self) -> f64 {
        // 无法直接从 OpenTelemetry 仪表盘获取值
        0.0
    }
    
    fn value_with_labels(&self, _label_values: &[&str]) -> f64 {
        // 无法直接从 OpenTelemetry 仪表盘获取值
        0.0
    }
}

/// OpenTelemetry 直方图适配器
struct OtelHistogramAdapter {
    histogram: OtelHistogram<f64>,
}

impl Histogram for OtelHistogramAdapter {
    fn record(&self, value: f64) {
        self.histogram.record(value, &[]);
    }
    
    fn record_with_labels(&self, value: f64, label_values: &[&str]) {
        self.histogram.record(value, &convert_labels(label_values));
    }
    
    fn buckets(&self) -> Vec<(f64, u64)> {
        // 无法直接从 OpenTelemetry 直方图获取桶
        Vec::new()
    }
    
    fn buckets_with_labels(&self, _label_values: &[&str]) -> Vec<(f64, u64)> {
        // 无法直接从 OpenTelemetry 直方图获取桶
        Vec::new()
    }
    
    fn count(&self) -> u64 {
        // 无法直接从 OpenTelemetry 直方图获取计数
        0
    }
    
    fn count_with_labels(&self, _label_values: &[&str]) -> u64 {
        // 无法直接从 OpenTelemetry 直方图获取计数
        0
    }
    
    fn sum(&self) -> f64 {
        // 无法直接从 OpenTelemetry 直方图获取总和
        0.0
    }
    
    fn sum_with_labels(&self, _label_values: &[&str]) -> f64 {
        // 无法直接从 OpenTelemetry 直方图获取总和
        0.0
    }
}

/// 将标签值转换为 OpenTelemetry KeyValue
fn convert_labels(label_values: &[&str]) -> Vec<KeyValue> {
    label_values.iter()
        .enumerate()
        .map(|(i, &value)| {
            KeyValue::new(format!("label_{}", i), value.to_string())
        })
        .collect()
}

/// OpenTelemetry 跟踪器
pub struct OtelTracer {
    /// 内部跟踪器
    tracer: OtelTracer,
    /// 活动跨度
    active_spans: dashmap::DashMap<String, opentelemetry::trace::TraceId>,
}

impl OtelTracer {
    /// 创建新的 OpenTelemetry 跟踪器
    pub fn new(tracer: OtelTracer) -> Self {
        Self {
            tracer,
            active_spans: dashmap::DashMap::new(),
        }
    }
    
    /// 转换 OpenTelemetry TraceId 为字符串
    fn trace_id_to_string(trace_id: opentelemetry::trace::TraceId) -> String {
        format!("{:032x}", trace_id.to_u128())
    }
    
    /// 转换 OpenTelemetry SpanId 为字符串
    fn span_id_to_string(span_id: opentelemetry::trace::SpanId) -> String {
        format!("{:016x}", span_id.to_u64())
    }
    
    /// 创建内部上下文
    fn create_internal_context(&self, context: Option<SpanContext>) -> opentelemetry::Context {
        if let Some(ctx) = context {
            // 创建父跨度上下文
            let trace_id = u128::from_str_radix(&ctx.trace_id, 16).unwrap_or(0);
            let span_id = u64::from_str_radix(&ctx.span_id, 16).unwrap_or(0);
            
            let trace_id = opentelemetry::trace::TraceId::from_u128(trace_id);
            let span_id = opentelemetry::trace::SpanId::from_u64(span_id);
            
            let trace_flags = if ctx.sampled {
                opentelemetry::trace::TraceFlags::SAMPLED
            } else {
                opentelemetry::trace::TraceFlags::default()
            };
            
            let trace_state = opentelemetry::trace::TraceState::default();
            
            let span_context = opentelemetry::trace::SpanContext::new(
                trace_id,
                span_id,
                trace_flags,
                false,
                trace_state,
            );
            
            return opentelemetry::Context::new().with_remote_span_context(span_context);
        }
        
        opentelemetry::Context::new()
    }
}

impl TracerTrait for OtelTracer {
    fn create_span(&self, name: &str, context: Option<SpanContext>) -> Box<dyn Span> {
        let otel_ctx = self.create_internal_context(context.clone());
        
        let mut span_builder = self.tracer.span_builder(name);
        span_builder.with_kind(SpanKind::Internal);
        
        let span = self.tracer.build_with_context(span_builder, &otel_ctx);
        let span_context = span.span_context();
        
        let our_context = SpanContext {
            trace_id: Self::trace_id_to_string(span_context.trace_id()),
            span_id: Self::span_id_to_string(span_context.span_id()),
            parent_span_id: context.and_then(|c| c.parent_span_id),
            sampled: span_context.is_sampled(),
        };
        
        Box::new(OtelSpanAdapter {
            span,
            context: our_context,
        })
    }
    
    fn start_span(&self, name: &str, context: Option<SpanContext>) -> (Box<dyn Span>, SpanContext) {
        let span = self.create_span(name, context);
        let ctx = span.context().clone();
        (span, ctx)
    }
    
    fn end_span(&self, context: SpanContext, _duration: Option<Duration>) {
        // OpenTelemetry 不支持显式设置持续时间，跨度在丢弃时自动结束
    }
    
    fn set_global_attributes(&self, attributes: &[(&str, &str)]) {
        // OpenTelemetry 不支持全局属性
    }
}

/// OpenTelemetry 跨度适配器
struct OtelSpanAdapter {
    /// 内部跨度
    span: OtelSpan,
    /// 我们的上下文
    context: SpanContext,
}

impl Span for OtelSpanAdapter {
    fn add_attribute(&self, key: &str, value: &str) {
        self.span.set_attribute(KeyValue::new(key, value.to_string()));
    }
    
    fn add_event(&self, name: &str, attributes: &[(&str, &str)]) {
        let attrs: Vec<KeyValue> = attributes.iter()
            .map(|(k, v)| KeyValue::new(*k, (*v).to_string()))
            .collect();
            
        self.span.add_event(name, attrs);
    }
    
    fn set_status(&self, status: SpanStatus, description: Option<&str>) {
        match status {
            SpanStatus::Ok => self.span.set_status(Status::Ok),
            SpanStatus::Error => {
                if let Some(desc) = description {
                    self.span.set_status(Status::error(desc));
                } else {
                    self.span.set_status(Status::error("Unknown error"));
                }
            }
            _ => {}
        }
    }
    
    fn end(&self, _duration: Option<Duration>) {
        self.span.end();
    }
    
    fn context(&self) -> &SpanContext {
        &self.context
    }
}

/// 完整的 OpenTelemetry 跟踪系统
pub struct OtelTelemetrySystem {
    /// 导出器
    exporter: OtelExporter,
    /// 指标系统
    metrics: Option<OtelMetrics>,
    /// 跟踪器
    tracer: Option<OtelTracer>,
}

impl OtelTelemetrySystem {
    /// 创建新的 OpenTelemetry 跟踪系统
    pub fn new(config: OtelConfig) -> Self {
        Self {
            exporter: OtelExporter::new(config),
            metrics: None,
            tracer: None,
        }
    }
}

impl TelemetrySystem for OtelTelemetrySystem {
    fn init(&self) -> Result<(), String> {
        let mut exporter = self.exporter.clone();
        exporter.init()?;
        
        if let Some(meter_provider) = exporter.get_meter_provider() {
            let provider_arc = unsafe { Arc::from_raw(meter_provider as *const dyn MeterProvider) };
            let metrics = OtelMetrics::new(provider_arc.clone());
            let _ = Arc::into_raw(provider_arc); // 防止释放
            
            // self.metrics = Some(metrics);
        }
        
        if let Some(tracer) = exporter.get_tracer() {
            // self.tracer = Some(OtelTracer::new(tracer.clone()));
        }
        
        Ok(())
    }
    
    fn shutdown(&self) -> Result<(), String> {
        self.exporter.shutdown()
    }
    
    fn create_counter(&self, name: &str, description: &str, labels: &[&str]) -> Box<dyn Counter> {
        if let Some(metrics) = &self.metrics {
            metrics.create_counter(name, description, labels)
        } else {
            Box::new(crate::telemetry::metrics::MemoryCounter::new(name, description, labels))
        }
    }
    
    fn create_gauge(&self, name: &str, description: &str, labels: &[&str]) -> Box<dyn Gauge> {
        if let Some(metrics) = &self.metrics {
            metrics.create_gauge(name, description, labels)
        } else {
            Box::new(crate::telemetry::metrics::MemoryGauge::new(name, description, labels))
        }
    }
    
    fn create_histogram(&self, name: &str, description: &str, labels: &[&str], buckets: &[f64]) -> Box<dyn Histogram> {
        if let Some(metrics) = &self.metrics {
            metrics.create_histogram(name, description, labels, buckets)
        } else {
            Box::new(crate::telemetry::metrics::MemoryHistogram::new(name, description, labels, buckets))
        }
    }
    
    fn tracer(&self) -> Box<dyn TracerTrait> {
        if let Some(tracer) = &self.tracer {
            Box::new(tracer.clone())
        } else {
            Box::new(crate::telemetry::tracing::MemoryTracer::new())
        }
    }
}

// 为了解决编译错误而添加的实现
impl Clone for OtelExporter {
    fn clone(&self) -> Self {
        Self {
            config: self.config.clone(),
            tracer: self.tracer.clone(),
            meter_provider: None, // 不能克隆
        }
    }
}

impl Clone for OtelTracer {
    fn clone(&self) -> Self {
        Self {
            tracer: self.tracer.clone(),
            active_spans: dashmap::DashMap::new(),
        }
    }
} 